其他
这代码居然有差别?CPU友好的代码该这样写
阿里妹导读
本文用实际用例阐述了用心组织的代码也能让性能提升百倍,我们不应该停留在CRUD的漩涡中。下面来看看这个神奇的现象。
一、震惊,这代码居然有差别!
二、为什么会有性能差别?
首先,我们需要知道Java二维数组的存储结构是什么样子的。 其次,我们需要知道CPU在计算的时候它L1、L2、L3的缓存机制。
2.1 知识点
2.1.1 知识点一 -- Java二维数组的存储结构
2.1.2 知识点二 -- CPU的缓存机制
L1 、L2、L3、主存 的大小是逐渐增大,速度是逐渐减小的。
2.2 性能损失的原因 -- 缓存命中率
2.2.1 友好的遍历方式
2.2.2 不友好的遍历方式
三、总结
四、附件
4.1 运行的环境
JMH version: 1.36
VM version: JDK 11.0.13, Java HotSpot(TM) 64-Bit Server VM, 11.0.13+10-LTS-370
型号名称:MacBook Pro
型号标识符:MacBookPro15,2
处理器名称:四核Intel Core i5
处理器速度:2.4 GHz
处理器数目:1
核总数:4
L2缓存(每个核):256 KB
L3缓存:6 MB
超线程技术:已启用
内存:16 GB
系统固件版本:1715.60.5.0.0 (iBridge: 19.16.10647.0.0,0)
import org.openjdk.jmh.annotations.*;
/**
* 矩阵 C = AB 的计算
*
* @author wzj
* @date 2023/02/09
*/
@BenchmarkMode(Mode.AverageTime)
@State(value = Scope.Benchmark)
// 预热3次
@Warmup(iterations = 3, time = 1)
// 循环 10 次
@Measurement(iterations = 10, time = 1)
public class ArrayTestBenchmark {
private final int N = 1000;
private final int[][] arrays_A = new int[N][N];
private final int[][] arrays_B = new int[N][N];
@Setup
public void setUp() {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
arrays_A[i][j] = i + j;
arrays_B[i][j] = i + j;
}
}
}
@Benchmark
public void ijk() {
final int[][] arrays_C = new int[N][N];
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
int sum = 0;
for (int k = 0; k < N; k++) {
sum += arrays_A[i][k] * arrays_B[k][j];
}
arrays_C[i][j] += sum;
}
}
assert arrays_C.length > 0;
}
@Benchmark
public void jik() {
final int[][] arrays_C = new int[N][N];
for (int j = 0; j < N; j++) {
for (int i = 0; i < N; i++) {
int sum = 0;
for (int k = 0; k < N; k++) {
sum += arrays_A[i][k] * arrays_B[k][j];
}
arrays_C[i][j] += sum;
}
}
assert arrays_C.length > 0;
}
@Benchmark
public void jki() {
final int[][] arrays_C = new int[N][N];
for (int j = 0; j < N; j++) {
for (int k = 0; k < N; k++) {
int r_B = arrays_B[k][j];
for (int i = 0; i < N; i++) {
arrays_C[i][j] += arrays_A[i][k] * r_B;
}
}
}
assert arrays_C.length > 0;
}
@Benchmark
public void kji() {
final int[][] arrays_C = new int[N][N];
for (int k = 0; k < N; k++) {
for (int j = 0; j < N; j++) {
int r_B = arrays_B[k][j];
for (int i = 0; i < N; i++) {
arrays_C[i][j] += arrays_A[i][k] * r_B;
}
}
}
assert arrays_C.length > 0;
}
@Benchmark
public void kij() {
final int[][] arrays_C = new int[N][N];
for (int k = 0; k < N; k++) {
for (int i = 0; i < N; i++) {
int r_A = arrays_A[k][i];
for (int j = 0; j < N; j++) {
arrays_C[i][j] += r_A * arrays_B[k][j];
}
}
}
assert arrays_C.length > 0;
}
@Benchmark
public void ikj() {
final int[][] arrays_C = new int[N][N];
for (int i = 0; i < N; i++) {
for (int k = 0; k < N; k++) {
int r_A = arrays_A[k][i];
for (int j = 0; j < N; j++) {
arrays_C[i][j] += r_A * arrays_B[k][j];
}
}
}
assert arrays_C.length > 0;
}
}
4.3 多次运行benchmark的结果
引用:
《深入理解计算机操作系统》 《深入理解Java虚拟机》